//
// Created by hsj on 2024-1-9.
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef WIN32
//windows minGW64
//inet_pton函数：_WIN32_WINNT
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600
#include <winsock2.h>
#include <ws2tcpip.h>
//#pragma comment(lib,"ws2_32.lib")
#else
//linux  gcc
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/wait.h>
#include <signal.h>
#endif
#define BUF_SIZE 30
//防止僵尸进程，
void read_childproc(int sig);

int main(int argc, char* argv[]){
    int fds1[2],fds2[2];
    char str1[]="Who are you?" ;
    char str2[]="Thank you for your message  ";
    char buf[BUF_SIZE];
    pid_t pid;

    /**
     * struct sigaction
       {
            void (*sa_handler)(int);
            sigset_t sa_mask;
            int sa_flags;
       }
        此结构体的sa_handler成 员保存信号处理函数的指针值(地址值)。
        sa_mask和sa_flags的所有位均初始化为0即可。这2个成员用于指定信号相关的选项和特性，而我们的目的主要是防止产生僵尸进程，故省略。

     */
    struct sigaction act;
    act.sa_handler=read_childproc;
    sigemptyset(&act.sa_mask);
    act.sa_flags=0;
    //注册子进程结束事件
    sigaction(SIGCHLD,&act, 0);

    pipe(fds1),pipe(fds2);
    pid=fork();
    if(pid == 0){/*子进程运行区域*/
        write(fds1[1], str1, sizeof(str1));
        read(fds2[0], buf,BUF_SIZE) ;
        printf("Child proc output: %s \n", buf);
        return 32;
    }else{/*父进程运行区域*/
        read(fds1[0], buf, BUF_SIZE);
        printf("Parent proc output: %s \n", buf);
        write(fds2[1], str2, sizeof(str2));
        sleep(3);//master等待 3 sec
    }

    return EXIT_SUCCESS;
}
void read_childproc(int sig){
    pid_t pid;
    int status;
    //非阻塞式退出进程
    //waitpid第一个参数：等待终止的目标子进程的ID，若传递-1，则与wait函数相同，可以等待任意子进程终止。
    pid=waitpid(-1, &status, WNOHANG);
    if(WIFEXITED(status)){//检测退出了吗
        printf("signal: Removed Child proc  id: %d \n", pid);
        printf("signal: Child send: %d \n", WEXITSTATUS(status));//获取退出的子进程的退出码/返回值
    }
}